/* Programa que despliega una imagen con formato BMP   para 2 a 16 colores*/
/* Realizado por: J. Antonio Jimenez Avia */
/* Tel. 796-16-78, 753-62-30.
   Hunab.
   ESCOM IPN.
   29/iv/96   Cd. de Mexico

En la actualidad existen en el mercado diversos tipos de formatos para almacenar
imagenes, su diversidad es muy grande. Algunos de los formatos mas populares
son GIF, TIFF, JPG, BMP, etc. Todos estos formatos son comerciales por lo cual
no es facil encontrar informacion interna sobre ellos.

Uno de los formatos mas sencillos es el BMP (Mapa de Bits). Un BMP como todo
archivo con formato consta de dos partes principales. Cabecera y cuerpo.

La cabecera esta compuesta de: la identificaron del formato del archivo,
direccion de inicio del cuerpo, tamao horizontal de la imagen, tamao vertical
de la imagen, el numero de bits por pixel y la paleta de colores.
Con la informacion de la cabecera obtenemos el tamao de imagen. el tipo de
resolucion del archivo (si es de 2, 16 o 256 colores), y la paleta de colores
propia de esa imagen.

En el cuerpo de la imagen se encuentra el valor del color de cada pixel, que
se ira acomodando en la posicion correspondiente de acuerdo al tamao de horizontal
y vertical, podemos pensar en algun momento que la imagen esta guardada de arriba
hacia abajo lo cual es falso. El primer pixel del cuerpo corresponde a la parte
inferior izquierda de la imagen, los demas pixeles se iran acomodando de izquierda
a derecha y de abajo hacia arriba.

La ubicacion de la informacion dentro del archivo es la siguiente:

BYTE    SIGNIFICADO                              nombre de la variable
0          Identificacion del archivo
10         Lugar donde empieza el cuerpo.          CUERPO
18         Tamao horizontal.                      TAM_X
22         Tamao vertical.                        TAM_Y
28         Bits por pixel.                         BIT_PIXEL
30         Principio de la paleta de colores.      PALETA
XX         El principio del cuerpo se calcula por medio de los bits por pixel
	    y la paleta de colores.

La paleta de colores es una tabla donde se tienen los colores de la imagen,
cada color esta formado de 4 componentes R,G,B,A donde R,G,B, indican la cantidad
de rojo, verde y azul de cada color, A es una mascara que nos indica como se
combinara ese color con los demas. Hay Que tener cuidado ya que la paleta de
colores esta escrita en el orden de B,G,R,A.

A continuacion se muestra un pequeo programa que despliega archivo con formato
BMP en la pantalla de la PC. */

/*modificado por Fernando Galindo Soria
  rutina propia para cambiar paleta
  rutina propia para traer el color del siguiente pixel 8/vi/96*/

#include <conio.h> //Cabeceras
#include <stdio.h>
#include <graphics.h>

FILE * BMP;
//Declaracion de variables
long int BIT_PIXEL, PIXEL_byte, CUERPO,
 PALETA, PALETA_TAM, TAM_X, TAM_Y;
int x,y,mask;
char huge col[100][100];
int ShowBMP(char* fname);
void cabecera(void);
void paleta(void);
void escrcolordac16(char color,char r,char g,char b);
void cuerpo(void);
int trae_pixel(void);

void main(void)
 {
    int gdriver=DETECT,gmode;
    initgraph(&gdriver,&gmode,"");
    ShowBMP("arches1.BMP");//poner el nombre del archivo donde esta la imagen a desplegar
    getch();
    closegraph();
 }

int ShowBMP(char* fname) 
//Funcion que abre el archivo y despliega la imagen en el monitor
 {
   BMP= fopen(fname,"rb");//abre el archivo de imagen
   if (BMP==NULL) return 1;

   cabecera();
   paleta();
   cuerpo();

   return 0;
 }

void cabecera(void)
{
 //lee la cabecera
   fseek(BMP,10,SEEK_SET);
   fread(&CUERPO,sizeof(CUERPO),1,BMP);//Lugar donde empieza el cuerpo.
   fseek(BMP,18,SEEK_SET);
   fread(&TAM_X,sizeof(TAM_X),1,BMP);  //Tamao horizontal.
   fseek(BMP,22,SEEK_SET);
   fread(&TAM_Y,sizeof(TAM_Y),1,BMP);  //Tamao vertical.
   fseek(BMP,28,SEEK_SET);
   fread(&BIT_PIXEL,sizeof(BIT_PIXEL),1,BMP);//Bits por pixel.
}

void paleta(void)
{  //lee del archivo la paleta de colores y la carga en la tarjeta de video
   typedef struct //Estructura para el color
   {
      unsigned char b, g, r, a;
   } Color;
   Color col;
   int k;
   PALETA_TAM=1<<BIT_PIXEL;
   PALETA=CUERPO-4*PALETA_TAM;         //Principio de la paleta de colores.

   fseek(BMP,PALETA,SEEK_SET);
   for (k=0;k<PALETA_TAM;k++)  //Cargando la paleta de colores
   {
     fread(&col,sizeof(col),1,BMP);
     escrcolordac16(k,k,k,k);
   }
}

/*cambia de color paleta llamando directamente a los puertos
  del convertidor analogico digital  de la tarjeta de video 31/iii/96

  utiliza initgraph y maneja paleta rgb de 16 colores b(lue) g(reen) r(ed)
    14/iv/96 */
void escrcolordac16(char color,char r,char g,char b)
{
 char indcol[]={0,1,2,3,4,5,20,7,56,57,58,59,60,61,62,63};
  outportb(0x3C8,indcol[color]);/*inicializa el color*/
  outportb(0x3C9,r);
  outportb(0x3C9,g);
  outportb(0x3C9,b);
}

void cuerpo(void)
{
   PIXEL_byte=8/BIT_PIXEL;             //numero de pixels por byte
   mask=(1<<BIT_PIXEL)-1;

   fseek(BMP,CUERPO,SEEK_SET);
   for (y=TAM_Y-1; y>=0; y--) //Despliega la imagen en el monitor
     for (x=0; x<TAM_X; x++){
       col[x][y]=trae_pixel();
       putpixel(x,y,col[x][y]+col[x-1][y]+col[x+1][y]+col[x][y-1]+col[x-1][y-1]+col[x+1][y-1]+col[x][y+1]+col[x-1][y+1]+col[x+1][y+1]);
       }
}

int trae_pixel(void) //Funcion que regresa el indice del color del siguiente pixel
{
 static int xi=0;
 static int n=0;
 static long int col[4];
 unsigned char b,b1[4];
 int k;

 if (xi%PIXEL_byte==0)    //desempaca los pixels empacados en un byte
 {
   fread(&b,sizeof(b),1,BMP);//trae un byte del archivo
   k=PIXEL_byte-1;
   col[k]= b & mask;     //desempaca cada pixel y lo almacena en un arreglo
   while (k--) col[k]=(b>>=BIT_PIXEL) & mask;
   n++;            //cuenta cuantos bytes ha desempacado
 }

 if (xi>=TAM_X)//cuando llega al final de una linea inicializa las variables
 {
   xi=0;
   fread(b1,1,(4-n%4)%4,BMP);//ignora bytes para quedar en multiplos de 4
   n=0;
 }

 return col[xi++%PIXEL_byte];//regresa el siguiente pixel
}

